/*
 * HMMChar.java
 *
 * Created on November 9, 2007, 11:23 AM
 *
 */
package Estimator.NGramChar;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 * @author Martin Haulrich
 */
public class HMMChar implements CharNGramEst {

    final CharNGramEst prior;

    final int priorN;

    Map<String, Double> cachePrior;

    Map<String, Double> cacheSeq;


    private double getCachedEstimate(String ngram) {
        Double res = cachePrior.get(ngram);
        if (res != null) {
            return res;
        }
        res = prior.getEstimate(ngram);
        cachePrior.put(ngram, res);
        return res;
    }


    /** Constructor */
    public HMMChar(CharNGramEst prior, int N) {

        this.prior = prior;
        if (N > prior.getN()) {
            System.err.println("Cannot model based on " + N + "-grams when prior only models " + prior.getN() + "-grams.");
            System.err.println("Basing model on " + prior.getN() + "-grams.");
            priorN = prior.getN();
        } else {
            priorN = N;
        }
        // cache = new HashMap<String,Double>();
        cachePrior = new LinkedHashMap<String, Double>(12800, 0.75F, true) {

            @Override
            protected boolean removeEldestEntry(Map.Entry<String, Double> eldest) {
                return size() > 10000;
            }
        };
        cacheSeq = new LinkedHashMap<String, Double>(12800, 0.75F, true) {

            @Override
            protected boolean removeEldestEntry(Map.Entry<String, Double> eldest) {
                return size() > 10000;
            }
        };
    }


    @Override
    public int getN() {
        return Integer.MAX_VALUE;
    }


    @Override
    public double getEstimate(String seq) {

        Double cest = cacheSeq.get(seq);
        if (cest != null) {
            return cest;
        }

        //     System.err.println("HMM: '" + seq + "'");
        double est = 0;
        for (int i = 0; i < seq.length() - 1; i++) {
            String ngram = seq.substring(i, Math.min(i + priorN, seq.length()));
            String subgram = seq.substring(i + 1, Math.min(i + priorN, seq.length()));

            double ngramProb = getCachedEstimate(ngram) - getCachedEstimate(subgram);
            //  System.err.println(prior.getEstimate(ngram)+ "  " +prior.getEstimate(subgram));
            //  System.err.println("ngram: " + ngram + "  subgram: " + subgram+ "   " + ngramProb);
            est = est + ngramProb;
        }
        cacheSeq.put(seq, est);
        return est;
    }


    @Override
    public void saveARPA(String filename) throws IOException {

    }
}
